package com.et.machine.util

import android.text.TextUtils
import android.util.Base64
import com.et.logger.ELog
import com.et.logger.TAGS
import com.et.machine.BuildConfig
import com.et.util.md5
import okhttp3.*
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit

private const val MY_APP_ID_MVV = BuildConfig.myappidMvv
private const val HTTP_KEY_MVV = BuildConfig.httpKeyMvv

val okHttpClient = OkHttpClient.Builder()
    .readTimeout(10, TimeUnit.SECONDS)
    .writeTimeout(10, TimeUnit.SECONDS)
    .connectTimeout(10, TimeUnit.SECONDS)
    .addInterceptor(LoggingInterceptor())
    .build()

data class Result(
    var success: Boolean = false,
    var code: Int = 0,
    var content: String = "unsuccessful"
)

enum class ApiProvider {
    MVV, BZP
}

object HttpUse {

    class Post(private val provider: ApiProvider = ApiProvider.MVV, val r: Result) {

        private val request = Request.Builder()
        private lateinit var map: HashMap<String, String>
        private var base64 = false
        private var call: Call? = null

        fun putUrl(url: String): Post {
            request.url(url)
            return this
        }

        fun putParam(_map: HashMap<String, String>): Post {
            map = _map
            return this
        }

        fun base64(_base64: Boolean): Post {
            base64 = _base64
            return this
        }

        fun build(): Post {
            SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).apply {
                map["datetime"] = format(System.currentTimeMillis())
            }
            map["myappid"] = MY_APP_ID_MVV
            val sign = when (provider) {
                ApiProvider.MVV -> {
                    sign(map, HTTP_KEY_MVV, base64)
                }
                ApiProvider.BZP -> {
                    sign(map, "BZP", base64)
                }
            }

            val string = StringBuilder(256)
            FormBody.Builder().also { formBody ->
                string.append('[').append("sign=").append(sign).append(',')
                formBody.add("sign", sign)
                map.forEach {
                    formBody.add(it.key, it.value)
                    string.append(it.key).append('=').append(it.value).append(',')
                }
                string.append(']')
                ELog.d(TAGS.machine, "okhttp request:${string}")
                request.post(formBody.build())
            }
            call = okHttpClient.newCall(request.build())
            return this
        }

        fun execute() {
            call?.apply {
                try {
                    execute().apply {
                        r.success = isSuccessful
                        r.code = code
                        r.content = (body?.string() ?: "unsuccessful").apply {
                            ELog.d(
                                TAGS.machine,
                                "okhttp response $this"
                            )
                        }
                    }
                } catch (e: IOException) {
                    r.success = false
                    r.content = e.message ?: "unknown"
                }
            }
        }

        fun cancel() {
            call?.cancel()
        }
    }


    fun sign(map: HashMap<String, String>, key: String, base64: Boolean): String {
        return try {
            map["key"] = key
            val keys = map.keys.toMutableList()
            keys.sortBy { it }
            val sb = StringBuilder(512)
            var obj: Any?
            for (k in keys) {
                if (TextUtils.isEmpty(k)) continue
                obj = map[k]
                if (obj == null) continue
                sb.append(k).append("=").append(obj.toString()).append("&")
            }
            map.remove("key")
            sb.delete(sb.length - 1, sb.length)
            var content = sb.toString()
            if (base64) content = Base64.encodeToString(content.toByteArray(), Base64.NO_WRAP)
            val str = md5(content).lowercase(Locale.getDefault())
            sb.clear()
            sb.append(str[1])
                .append(str[3])
                .append(str[5])
                .append(str.substring(7))
                .append(str[0])
                .append(str[2])
                .append(str[4])
                .append(str[6])
            md5(sb.toString()).lowercase(Locale.getDefault())
        } catch (e: Exception) {
            ELog.d(TAGS.machine, "Sign Failed：${e.message ?: "unknown"}")
            e.message ?: "unknown"
        }
    }
}

internal class LoggingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()
        val t1 = System.nanoTime()
        ELog.d(
            TAGS.machine,
            "okhttp3 request ${request.url} on ${chain.connection()} ${request.headers}",
        )
        val response: Response = chain.proceed(request)
        val t2 = System.nanoTime()
        ELog.d(
            TAGS.machine,
            "Received response ${response.request.url} in ${(t2 - t1) / 1e6}ms ${response.code}",
        )
        return response
    }
}